﻿namespace UnitTest_MSTestHelper
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class When_creating_a_delegate_for_a_method
    {
        private static List<string> hits = new List<string>();

        [TestMethod]
        public void Can_create_delegate_for_a_void_static_method()
        {
            var @delegate = typeof(When_creating_a_delegate_for_a_method)
                .GetMethod("PrivateStaticVoidMethod", BindingFlags.Static | BindingFlags.NonPublic)
                .CreateDelegate<Action<string>>();

            hits.Clear();
            @delegate("Bob");

            AssertEx.That(() => hits.SequenceEqual(new string[] { "Bob" }));
        }

        private static void PrivateStaticVoidMethod(string parameter)
        {
            hits.Add(parameter);
        }

        [TestMethod]
        public void Can_create_delegate_for_a_static_function()
        {
            var @delegate = typeof(When_creating_a_delegate_for_a_method)
                .GetMethod("PrivateStaticFunction", BindingFlags.Static | BindingFlags.NonPublic)
                .CreateDelegate<Func<string, int>>();

            hits.Clear();
            var result = @delegate("Bob");

            AssertEx.That(() => result == 314);
            AssertEx.That(() => hits.SequenceEqual(new string[] { "Bob" }));
        }

        private static int PrivateStaticFunction(string parameter)
        {
            hits.Add(parameter);

            return 314;
        }

        [TestMethod]
        public void Can_create_delegate_for_an_instance_method()
        {
            var @delegate = typeof(When_creating_a_delegate_for_a_method)
                .GetMethod("PrivateInstanceMethod", BindingFlags.Instance | BindingFlags.NonPublic)
                .CreateDelegate<Action<When_creating_a_delegate_for_a_method, string>>();

            hits.Clear();
            @delegate(this, "Bob");

            AssertEx.That(() => hits.SequenceEqual(new string[] { "Bob" }));
        }

        private void PrivateInstanceMethod(string parameter)
        {
            hits.Add(parameter);
        }

        [TestMethod]
        public void Can_create_delegate_for_an_instance_function()
        {
            var @delegate = typeof(When_creating_a_delegate_for_a_method)
                .GetMethod("PrivateInstanceFunction", BindingFlags.Instance | BindingFlags.NonPublic)
                .CreateDelegate<Func<When_creating_a_delegate_for_a_method, string, int>>();

            hits.Clear();
            var result = @delegate(this, "Bob");

            AssertEx.That(() => result == 314);
            AssertEx.That(() => hits.SequenceEqual(new string[] { "Bob" }));
        }

        private int PrivateInstanceFunction(string parameter)
        {
            hits.Add(parameter);

            return 314;
        }
    }
}